module ProcessQueue.Queue exposing (..)
-- 线程队列
import Array as A exposing (Array)
import ProcessQueue.Model exposing (..)
import Html as H
import Html.Attributes as HA


view : Queue -> H.Html msg
view queue =
 H.div
  []
  [ H.div 
      [ HA.class "row", HA.class "row1" ]
      (boxes (A.get 0 queue))
  , H.div 
      [ HA.class "row", HA.class "row2" ]
      (boxes (A.get 1 queue))
  , H.div 
      [ HA.class "row", HA.class "row3" ]
      (boxes (A.get 2 queue))
  ]

boxes : Maybe (Array PCB) -> List (H.Html msg)
boxes array = 
 case array of
  Nothing -> [H.text "A empty li"]
  Just array ->
   List.map (\pcb -> H.div [HA.class "box"] (pcb_html pcb)) (A.toList array)


show : Queue -> String
show queue =
  A.foldl (\nest_queue print -> print ++ (A.foldl (\pcb acc -> acc ++ (print_pcb pcb)) "队列: " nest_queue)) "" queue

safe_lis : Maybe (Array PCB) -> List (H.Html msg)
safe_lis array = 
 case array of
  Nothing -> [H.text "A empty li"]
  Just array ->
   List.map (\pcb -> H.li [] [H.text (print_pcb pcb)]) (A.toList array)

print_pcb : PCB -> String
print_pcb pcb 
  = "name: " 
  ++ (.name pcb) 
  ++ ", cost: " 
  ++ ((.cost >> toString) pcb) 
  ++ ", processed: " 
  ++ ((.processed >> toString) pcb)

pcb_html : PCB -> List (H.Html msg)
pcb_html pcb = 
 let percent = pcb_process_percent pcb
 in
  H.div [] [H.text (.name pcb)]
  :: H.div [] [H.text (((.processed >> toString) pcb) ++ "/" ++ ((.cost >> toString) pcb))]
  :: H.div 
       [HA.class "cssProgress"] 
       [ H.div 
           [HA.class "progress2"] 
           [ H.div 
               [HA.class "cssProgress-bar"
               ,HA.class "cssProgress-active"
               ,HA.class "cssProgress-success"
               ,HA.style [("width",percent)] 
               ]
               [ H.span [HA.class "cssProgress-label"] [H.text percent]]
           ] 
       ]
  :: []

-- 计算百分比画成进度条
pcb_process_percent : PCB -> String
pcb_process_percent pcb = 
  let cost = ((.cost >> toFloat) pcb)
      processed = ((.processed >> toFloat) pcb)
  in  ((floor >> toString) (processed / cost * 100)) ++ "%"
  

inner_pcb : Int -> Int -> Queue -> Maybe PCB
inner_pcb x y queue = A.get x queue |> Maybe.andThen (A.get y)
  

mock_queue : Queue
mock_queue = 
  A.fromList 
  [ A.fromList 
      [ PCB "p0" 100 0
      , PCB "p1" 10 0
      , PCB "p2" 17 0
      , PCB "p3" 7 0
      ]
  , A.fromList [PCB "p4" 19 0,PCB "p5" 21 0]
  , A.fromList [PCB "p6" 9 0]
  ]


with_new_process : Queue -> PCB -> Queue
with_new_process old_queue pcb =
 case (A.get 0 old_queue) of
  Nothing -> old_queue
  Just queue -> A.set 0 (A.push pcb queue) old_queue

-- 处理pointer所在pcb
process : Int -> Queue -> Queue
process point queue = 
 case A.get point queue of
  Nothing -> queue
  Just nest_queue ->
   case A.get 0 nest_queue of
    Nothing -> queue
    Just pcb -> 
     let processed_pcb = {pcb | processed = (.processed pcb) + 1}
     in A.set point (A.set 0 processed_pcb nest_queue) queue


is_point_pcb_completed : Pointer -> Queue -> Bool
is_point_pcb_completed p q  = 
  case inner_pcb p 0 q of
   Nothing -> False
   Just pcb -> (.cost pcb) <= (.processed pcb)

-- 移除当前指针所指队列的第一个pcb并返回(Maybe PCB,整个队列)
remove_point_pcb : Pointer -> Queue -> (Maybe PCB,Queue)
remove_point_pcb p queue = 
  let maybe_pcb = inner_pcb p 0 queue
      maybe_nest_queue = A.get p queue
  in case maybe_nest_queue of
    Nothing -> (Nothing,queue)
    Just nest_queue ->
      (maybe_pcb,A.set p (A.slice 1 (A.length nest_queue) nest_queue) queue)

is_pointing_last : Pointer -> Queue -> Bool
is_pointing_last p q = p == A.length q - 1

with_pcb_at_end : Pointer -> Queue -> PCB -> Queue
with_pcb_at_end p q pcb =
  case A.get p q of
    Nothing -> q
    Just nest_queue -> A.set p (A.push pcb nest_queue) q 

-- 将当前指向的pcb移动到下一队列
-- 如果该队列已经是底端，将pcb移动到队列尾部
point_pcb_down : Pointer -> Queue -> Queue
point_pcb_down p queue =
  let (maybe_pcb,new_queue) = remove_point_pcb p queue
  in case maybe_pcb of
    Nothing -> new_queue
    Just pcb -> 
      if is_pointing_last p new_queue then
        with_pcb_at_end p new_queue pcb
      else
        with_pcb_at_end (p+1) new_queue pcb


is_pointing_empty : Pointer -> Queue -> Bool
is_pointing_empty p q =
  case A.get p q of
    Nothing -> False
    Just nest_queue -> A.isEmpty nest_queue


new_acc : Pointer -> Acc
new_acc p =
  case p of
      0 -> Acc 0 1
      1 -> Acc 0 2
      2 -> Acc 0 4
      _ -> Acc 0 0